#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
#include <sstream>
#include "tiles.h"
#include "milkrace.h"

SDL_Event event;
SDL_Surface *display;
SDL_Surface *font;
R8B_Tiled_Screen *scr;

std::list<int> stack;

void print_stack() {
  std::ostringstream o;

  o << "stack~ ";
  std::copy(stack.begin(), stack.end(), std::ostream_iterator<int>(o, " "));
  r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, o.str().c_str());
}

bool handle_line(const std::string &line) {
  std::ostringstream o;
  int i;
  bool ok = true;

  r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "");
  //o << line.size() << " ~ '" << line << '\'';
  //r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, o.str().c_str());
  if(line[0] == '$') {
    std::istringstream in(line.substr(1));
    if(in >> std::hex >> i) stack.push_front(i); else ok = false;
  } else if (line.find_first_not_of("1234567890") == std::string::npos) {
    std::istringstream in(line);
    if(in >> i) stack.push_front(i); else ok = false;
  } else if(line == "+") {
    if(stack.size() >= 2) {
      int x = stack.front();
      stack.pop_front();
      int y = stack.front();
      // stack.pop_front();
      // stack.push_front(x + y);
      stack.front() = x + y;
    } else {
      r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "too few elements on stack!");
      ok = false;
    }
  } else if(line == "-") {
    if(stack.size() >= 2) {
      int x = stack.front();
      stack.pop_front();
      int y = stack.front();
      stack.front() = x - y;
    } else {
      r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "too few elements on stack!");
      ok = false;
    }
  } else if(line == "*") {
    if(stack.size() >= 2) {
      int x = stack.front();
      stack.pop_front();
      int y = stack.front();
      stack.front() = x * y;
    } else {
      r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "too few elements on stack!");
      ok = false;
    }
  } else if(line == "/") {
    if(stack.size() >= 2) {
      int x = stack.front();
      stack.pop_front();
      int y = stack.front();
      stack.front() = x / y;
    } else {
      r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "too few elements on stack!");
      ok = false;
    }
  } else if(line == "swap") {
      if(stack.size() >= 2) {
      int x = stack.front();
      stack.pop_front();
      int y = stack.front();
      stack.pop_front();
      stack.push_front(x);
      stack.push_front(y);
    } else {
      r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "too few elements on stack!");
      ok = false;
    }
  } else if(line == "dup") {
    stack.push_front(stack.front());
  }
  else if(line == "print") print_stack();
  else if(line == "quit") return false;
  else ok = false;
  if(ok) r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "ok");
  else r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "error");
  return true;
}

int main(int argc, char **argv) {
  std::string line;
  bool running = true;
  SDL_Rect rect = { 30, 20, 640, 480 };

  if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
    std::cerr << SDL_GetError() << std::endl;
    return 5;
  }
  atexit(SDL_Quit);
  display = SDL_SetVideoMode(640, 400, 32, SDL_HWSURFACE/*|SDL_FULLSCREEN*/);
  if(display == NULL) {
    std::cerr << "Video mode failed!\n";
    return 5;
  }
  SDL_EnableUNICODE(1);
  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
  font = get_milkrace_surfaceX2();
  // This actually makes it slower...?
  // {
  //   SDL_Surface *font_ = get_milkrace_surfaceX2();
  //   font = SDL_DisplayFormat(font_);
  //   if(font != NULL) {
  //     SDL_FreeSurface(font_);
  //   } else {
  //     font = font_;
  //   }
  // }
  if((scr = r8b_createTiledScreen_using_surface(40, 25, ' ', font, 16, 16)) == NULL) {
    std::cerr << "Aborting! Error while creating tiled screen.\n";
    return 5;
  }
  r8b_addCursorTiledScreen(scr, SDL_MapRGBA(display->format, 0x02, 0x88, 0x0b, 0x80), 500);
  r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "ok");
  while(running) {
    SDL_Delay(66);
    SDL_FillRect(display, NULL, SDL_MapRGB(display->format, 0xff, 0xff, 0xff));
    r8b_blitScreenXY(scr, display, 0, 0);
    SDL_Flip(display);
    while(SDL_PollEvent(&event) != 0) {
      switch(event.type) {
      case SDL_KEYDOWN:
	if(event.key.keysym.sym == SDLK_ESCAPE)
	  running = false;
	else if(event.key.keysym.sym == SDLK_BACKSPACE) {
	  if(line.size() > 0) {
	    if(scr->crsr_x > 0) {
	      --scr->crsr_x;
	      r8b_pokeScreen(scr, scr->crsr_x, scr->crsr_y, scr->default_fill);
	      line.resize(line.size() - 1);
	    }
	  }
	}
	else if((event.key.keysym.unicode != 0) && ((event.key.keysym.unicode & 0xFF80) == 0)) {
	  char ch = tolower(event.key.keysym.unicode & 0x7F);
	  //std::cout << (int)ch << '\n';
	  if(ch == 13) {
	    if(0 != line.size()) {
	      running = handle_line(line);
	      line.clear();
	    } else r8b_printStringScreenLn(scr, r8b_c64CharConversionFun, "");
	  } else {
	    r8b_putCharScreen(scr, r8b_c64CharConversionFun(ch));
	    line.push_back(ch);
	  }
	}
	break;
      default:
	break;
      }
    }
  }
  r8b_freeTiledScreen(scr);
  SDL_FreeSurface(font);
  SDL_FreeSurface(display);
  return 0;
};
